package registration.servlet;

import static org.junit.Assert.*;

import java.net.HttpURLConnection;
import java.util.*;

import msg.*;

import org.apache.wink.client.*;
import org.json.*;
import org.junit.*;
import org.junit.Test;

import registration.*;
import user.*;

import common.dal.Transaction;
import common.servlet.ManagersBundle;

@SuppressWarnings({"javadoc"})
public class ConsensusResourceTest extends EventResourceTest {
	private static String	CONSENSUSES;
	private long			eventId;
	
	@BeforeClass
	public static void setupBeforeClass() throws Exception {
		EventResourceTest.setupBeforeClass();
		CONSENSUSES = getResources() + "cons";
	}
	
	@Override
	public void setupServlets() throws Exception {
		t.commit();
		eventId = postEvent().first;
	}
	
	@Override
	@Test
	public void testPost() throws Exception {
		// test with bad cookie
		long id = postEvent().first;
		JSONObject object = new JSONObject("{name: 'conName'}");
		Resource res = rc.resource(EVENTS + "/" + id + "/cons");
		ClientResponse response = res.cookie(createCookie("12345")).post(object);
		assertEquals(HttpURLConnection.HTTP_UNAUTHORIZED, response.getStatusCode());
		// test with existing cookie belonging to other person
		t = new Transaction();
		User user2 = LoginManager.getNewInstance(t).registerUser("b" + new Date().getTime(), "bla", PASSWORD);
		long sessionId = LoginManager.getNewInstance(t).loginUser(user2.getLogin(), PASSWORD).getId();
		t.commit();
		response = res.cookie(createCookie(sessionId)).post(object);
		assertEquals(HttpURLConnection.HTTP_UNAUTHORIZED, response.getStatusCode());
		// ok login
		response = res.cookie(createCookie(cookie)).post(object);
		assertEquals(HttpURLConnection.HTTP_CREATED, response.getStatusCode());
	}
	
	@Override
	@Test
	public void testRetrieve() throws Exception {
		Resource res = rc.resource(CONSENSUSES + "/101");
		ClientResponse response = res.get();
		assertEquals(HttpURLConnection.HTTP_NOT_FOUND, response.getStatusCode());
		addCon();
	}
	
	@Override
	public void testList() throws Exception {
		// normal get in bad path
		ClientResponse response = rc.resource(CONSENSUSES).get();
		assertEquals(HttpURLConnection.HTTP_BAD_METHOD, response.getStatusCode());
		// get for fake event
		Resource res = rc.resource(EVENTS + "/101/cons");
		response = res.get();
		assertEquals(HttpURLConnection.HTTP_NOT_FOUND, response.getStatusCode());
		// empty get
		JSONArray array = new JSONArray();
		res = rc.resource(EVENTS + "/" + eventId + "/cons");
		response = res.get();
		assertEquals(HttpURLConnection.HTTP_OK, response.getStatusCode());
		assertEquals(array, response.getEntity(JSONArray.class));
		// get with item
		Consensus con = addCon();
		response = res.get();
		assertEquals(HttpURLConnection.HTTP_OK, response.getStatusCode());
		try (ManagersBundle mb = new ManagersBundle()) {
			array.put(EventResource.conToJson(con, mb, null));
			assertEquals(array, response.getEntity(JSONArray.class));
		}
	}
	
	@Test
	public void testConWithCookie() throws Exception {
		JSONObject vote = new JSONObject("{vote: 'false'}");
		Consensus con = addCon();
		t = new Transaction();
		RegistrationManager.getNewInstance(t).registerUserForEvent(getUser(), con.getEvent());
		t.commit();
		long conId = con.getId();
		Resource res = rc.resource(CONSENSUSES + "/" + conId + "/votes").cookie(createCookie(cookie));
		// vote on correct event
		ClientResponse response = res.post(vote);
		assertEquals(HttpURLConnection.HTTP_CREATED, response.getStatusCode());
		try (ManagersBundle mb = new ManagersBundle()) {
			JSONObject object = EventResource.conToJson(con, mb, getUser());
			assertEquals(object, rc.resource(CONSENSUSES + "/" + conId).cookie(createCookie(cookie)).get()
					.getEntity(JSONObject.class));
		}
	}
	
	@Test
	public void testVote() throws Exception {
		JSONObject vote = new JSONObject("{vote: 'false'}");
		// vote with bad cookie
		Resource res = rc.resource(CONSENSUSES + "/101/votes");
		ClientResponse response = res.cookie(createCookie("12345")).post(vote);
		assertEquals(HttpURLConnection.HTTP_UNAUTHORIZED, response.getStatusCode());
		// vote on bad consensus
		response = res.cookie(createCookie(cookie)).post(vote);
		assertEquals(HttpURLConnection.HTTP_NOT_FOUND, response.getStatusCode());
		// vote with cookie not registered
		Consensus con = addCon();
		long conId = con.getId();
		res = rc.resource(CONSENSUSES + "/" + conId + "/votes").cookie(createCookie(cookie));
		response = res.post(vote);
		assertEquals(HttpURLConnection.HTTP_BAD_REQUEST, response.getStatusCode());
		// vote on correct event
		t = new Transaction();
		RegistrationManager.getNewInstance(t).registerUserForEvent(getUser(), con.getEvent());
		t.commit();
		response = res.post(vote);
		assertEquals(HttpURLConnection.HTTP_CREATED, response.getStatusCode());
		Resource voteRes = rc.resource(response.getHeaders().getFirst("location"));
		assertFalse(voteRes.get().getEntity(Boolean.class));
		// vote again with different vote
		vote.put("vote", true);
		response = res.post(vote);
		assertEquals(HttpURLConnection.HTTP_OK, response.getStatusCode());
		assertTrue(voteRes.get().getEntity(Boolean.class));
		// vote event over
		Calendar cal = Calendar.getInstance();
		cal.add(Calendar.MILLISECOND, 200);
		t = new Transaction();
		EventMessage event = MessageManager.getNewInstance(t)
				.createNewEventMessage(new Location(1, 0.5), "blabla2", getUser(), cal, 1);
		RegistrationManager.getNewInstance(t).registerUserForEvent(getUser(), event);
		conId = RegistrationManager.getNewInstance(t).addConsensus(event, "blabla3").getId();
		t.commit();
		res = rc.resource(CONSENSUSES + "/" + conId + "/votes").cookie(createCookie(cookie));
		response = res.post(vote);
		assertTrue(voteRes.get().getEntity(Boolean.class));
		Thread.sleep(200);
		response = res.post(vote);
		assertEquals(HttpURLConnection.HTTP_BAD_REQUEST, response.getStatusCode());
		assertTrue(voteRes.get().getEntity(Boolean.class));
	}
	
	@Test
	public void testGetVote() throws Exception {
		// get vote of bad conId
		Resource res = rc.resource(CONSENSUSES + "/101/votes/101");
		ClientResponse response = res.get();
		assertEquals(HttpURLConnection.HTTP_NOT_FOUND, response.getStatusCode());
		// get vote of bad userId
		Consensus con = addCon();
		long conId = con.getId();
		res = rc.resource(CONSENSUSES + "/" + conId + "/votes/101");
		response = res.get();
		assertEquals(HttpURLConnection.HTTP_NOT_FOUND, response.getStatusCode());
		// get vote of user not voted
		t = new Transaction();
		RegistrationManager.getNewInstance(t).registerUserForEvent(getUser(), con.getEvent());
		t.commit();
		res = rc.resource(CONSENSUSES + "/" + conId + "/votes/" + getUser().getId());
		response = res.get();
		assertEquals(HttpURLConnection.HTTP_NOT_FOUND, response.getStatusCode());
		// get real vote
		t = new Transaction();
		RegistrationManager.getNewInstance(t).vote(con, getUser(), false);
		t.commit();
		response = res.get();
		assertEquals(HttpURLConnection.HTTP_OK, response.getStatusCode());
		assertEquals(false, response.getEntity(Boolean.class));
	}
	
	@Test
	public void testReached() throws Exception {
		// test bad conId
		Resource res = rc.resource(CONSENSUSES + "/101/hasReached");
		ClientResponse response = res.get();
		assertEquals(HttpURLConnection.HTTP_NOT_FOUND, response.getStatusCode());
		// test reached
		Consensus con = addCon();
		long conId = con.getId();
		res = rc.resource(CONSENSUSES + "/" + conId + "/hasReached");
		response = res.get();
		assertEquals(HttpURLConnection.HTTP_OK, response.getStatusCode());
		assertNull(response.getEntity(Boolean.class));
		// test not reached
		t = new Transaction();
		RegistrationManager.getNewInstance(t).registerUserForEvent(getUser(), con.getEvent());
		t.commit();
		response = res.get();
		assertEquals(HttpURLConnection.HTTP_OK, response.getStatusCode());
		assertNull(response.getEntity(Boolean.class));
		// test reached again
		t = new Transaction();
		RegistrationManager.getNewInstance(t).vote(con, getUser(), false);
		t.commit();
		response = res.get();
		assertEquals(HttpURLConnection.HTTP_OK, response.getStatusCode());
		assertFalse(response.getEntity(Boolean.class));
	}
	
	@Test
	public void testGetVotes() throws Exception {
		// test bad conId
		Resource res = rc.resource(CONSENSUSES + "/101/votes");
		ClientResponse response = res.get();
		assertEquals(HttpURLConnection.HTTP_NOT_FOUND, response.getStatusCode());
		// test empty
		JSONArray array = new JSONArray();
		Consensus con = addCon();
		res = rc.resource(CONSENSUSES + "/" + con.getId() + "/votes");
		response = res.get();
		assertEquals(HttpURLConnection.HTTP_OK, response.getStatusCode());
		assertEquals(array, response.getEntity(JSONArray.class));
		// test not empty
		t = new Transaction();
		RegistrationManager.getNewInstance(t).registerUserForEvent(getUser(), con.getEvent());
		RegistrationManager.getNewInstance(t).vote(con, getUser(), false);
		t.commit();
		array.put(new JSONObject("{userId: '" + getUser().getId() + "', vote: false}"));
		response = res.get();
		assertEquals(HttpURLConnection.HTTP_OK, response.getStatusCode());
		assertEquals(array, response.getEntity(JSONArray.class));
	}
	
	@Override
	public void testDelete() throws Exception {
		// do nothing
	}
	
	@Override
	public void testRegister() throws Exception {
		// do nothing
	}
	
	@Override
	public void testUnregister() throws Exception {
		// do nothing
	}
	
	@Override
	public void testListRegistered() throws Exception {
		// do nothing
	}
	
	@Override
	public void testRadius() throws Exception {
		// do nothing
	}
	
	@Override
	public void testSince() throws Exception {
		// do nothing
	}
	
	@Override
	public void testPast() throws Exception {
		// do nothing
	}
	
	private Consensus addCon() throws Exception {
		ClientResponse response;
		t = new Transaction();
		Consensus con = RegistrationManager.getNewInstance(t).addConsensus((EventMessage)MessageManager
				.getNewInstance(t).get(eventId), "nameyMcNameName");
		t.commit();
		response = rc.resource(CONSENSUSES + "/" + con.getId()).get();
		assertEquals(HttpURLConnection.HTTP_OK, response.getStatusCode());
		try (ManagersBundle mb = new ManagersBundle()) {
			assertEquals(EventResource.conToJson(con, mb, null), response.getEntity(JSONObject.class));
			mb.commit();
			return con;
		}
	}
}
